using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using LuaInterface;

using SlimDX;
using SlimDX.Direct3D9;
using SlimDX.Windows;

using miciv.Rendering;
using miciv.Misc;

namespace miciv
{
    public class XmlListenerUI : XmlListener
    {
        protected Stack<Frame> m_stckFrames;
        protected Stack<Scene> m_stckScenes;
        protected Frame m_currFrame;
        protected UIManager m_uiManager;
        protected LuaManager m_luaManager;
        protected Scene m_currScene;
        protected DataSourceManager m_dataSourceManager;

        public XmlListenerUI()
        {
            this.m_stckFrames = new Stack<Frame>();
            this.m_stckScenes = new Stack<Scene>();
            this.m_currFrame = null;
            this.m_uiManager = null; ;
            this.m_luaManager = null; ;
            this.m_currScene = null; ;

            this.Subscribe("ui", this.uiStartTagEventHandler, this.uiEndTagEventHandler);
            this.Subscribe("scene", this.sceneStartTagEventHandler, this.sceneEndTagEventHandler);
            this.Subscribe("size", this.sizeStartTagEventHandler, this.sizeEndTagEventHandler);
            this.Subscribe("position", this.positionStartTagEventHandler, this.positionEndTagEventHandler);
            this.Subscribe("color", this.colorStartTagEventHandler, this.colorEndTagEventHandler);
            this.Subscribe("colorrect", this.colorrectStartTagEventHandler, this.colorrectEndTagEventHandler);
            this.Subscribe("text", this.textStartTagEventHandler, this.textEndTagEventHandler);
            this.Subscribe("texcolrect", this.texcolrectStartTagEventHandler, this.texcolrectEndTagEventHandler);
            this.Subscribe("children", this.childrenStartTagEventHandler, this.childrenEndTagEventHandler);
            this.Subscribe("scale", this.scaleStartTagEventHandler, this.scaleEndTagEventHandler);
            this.Subscribe("template", this.templateStartTagEventHandler, this.templateEndTagEventHandler);
            this.Subscribe("templatelist", this.templatelistStartTagEventHandler, this.templatelistEndTagEventHandler);
            this.Subscribe("parameters", this.parametersStartTagEventHandler, this.parametersEndTagEventHandler);
            this.Subscribe("textparameter", this.textparameterStartTagEventHandler, this.textparameterEndTagEventHandler);
            this.Subscribe("layout", this.layoutStartTagEventHandler, this.layoutEndTagEventHandler);
        }

        public void Initialize(UIManager _uiManager, CoreContext _coreContext, XmlTraverser _xmlTraverser)
        {
            base.Initialize(_coreContext, _xmlTraverser);
            this.m_uiManager = _uiManager;
            this.m_luaManager = this.m_coreContext.GetData<LuaManager>("LuaManager");
            this.m_dataSourceManager = this.m_coreContext.GetData<DataSourceManager>("DataSourceManager");
        }

        protected void PushCurrentFrame(Frame _frame)
        {
            this.m_stckFrames.Push(this.m_currFrame);
            this.m_currFrame = _frame;
        }

        protected void PopCurrentFrame()
        {
            this.m_currFrame = this.m_stckFrames.Pop();
        }

        protected void PushCurrentScene(Scene _scene)
        {
            this.m_stckScenes.Push(this.m_currScene);
            this.m_currScene = _scene;
        }

        protected void PopCurrentScene()
        {
            this.m_currScene = this.m_stckScenes.Pop();
        }

        protected void ReadFrameAttributes(Frame _frame, XmlAttributeCollection _xmlAttributes)
        {
            XmlAttribute xmlAttr = _xmlAttributes.GetNamedItem("controlid") as XmlAttribute;
            if (null != xmlAttr)
            {
                _frame.ScriptControlID = xmlAttr.Value;
                _frame.ScriptControlPath = string.Format("{0}.controls.{1}", this.m_currScene.ID, _frame.ScriptControlID);
                _frame.ScriptControl = this.m_luaManager.GetTable(_frame.ScriptControlPath);
            }
            xmlAttr = _xmlAttributes.GetNamedItem("datasourceid") as XmlAttribute;
            if (null != xmlAttr)
            {
                _frame.DataSourceName = _xmlAttributes["datasourceid"].Value;
                _frame.DataSource = this.m_dataSourceManager.Get(_frame.DataSourceName);
            }
            xmlAttr = _xmlAttributes.GetNamedItem("inheritsdatasource") as XmlAttribute;
            if (null != xmlAttr)
            {
                _frame.InheritsDataSource = bool.Parse(_xmlAttributes["inheritsdatasource"].Value);
            }
        }

        protected bool uiStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            UI uiFrame = new UI(this.m_coreContext, _xmlAttributes["id"].Value, this.m_currFrame);
            this.ReadFrameAttributes(uiFrame, _xmlAttributes);
            uiFrame.Size = new Vector2(m_uiManager.Width, m_uiManager.Height);
            this.PushCurrentFrame(uiFrame);
            return true;
        }

        protected bool uiEndTagEventHandler(string _strName)
        {
            this.PopCurrentFrame();
            return true;
        }

        protected bool sceneStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            if (null == this.m_currScene)
            {
                string strScene = _xmlAttributes["id"].Value;
                if (null == this.m_uiManager.GetScene(strScene))
                {
                    Scene scnFrame = new Scene(this.m_coreContext, strScene, this.m_currFrame);
                    this.m_currScene = scnFrame;
                    this.ReadFrameAttributes(scnFrame, _xmlAttributes);
                    this.PushCurrentFrame(scnFrame);
                    return true;
                }
                throw new Exception(string.Format("{0} has already been declared", strScene));
            }
            throw new Exception("Nested scenes/templates are not allowed");
        }

        protected bool sceneEndTagEventHandler(string _strName)
        {
            Scene scnFrame = this.m_currFrame as Scene;
            this.m_uiManager.AddScene(scnFrame);
            this.PopCurrentFrame();
            this.m_currScene.Visible = false;
            this.m_currScene = null;
            return true;
        }

        protected bool sizeStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            this.m_currFrame.Size = new Vector2(float.Parse(this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "x", "0.0")),
                float.Parse(this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "y", "0.0")));
            this.m_currFrame.AutoResize = bool.Parse(this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "autoresize", "false"));
            return true;
        }

        protected bool sizeEndTagEventHandler(string _strName)
        {
            return true;
        }

        protected bool positionStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            this.m_currFrame.Position = new Vector2(float.Parse(this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "x", "0.0")),
                float.Parse(this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "y", "0.0")));
            return true;
        }

        protected bool positionEndTagEventHandler(string _strName)
        {
            return true;
        }

        protected bool colorStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            IDiffuse diffuse = this.m_currFrame as IDiffuse;
            if (null != diffuse)
            {
                diffuse.Diffuse = new Color4(
                    float.Parse(this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "a", "0.0")),
                    float.Parse(this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "r", "0.0")),
                    float.Parse(this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "g", "0.0")),
                    float.Parse(this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "b", "0.0")));
            }
            return true;
        }

        protected bool colorEndTagEventHandler(string _strName)
        {
            return true;
        }

        protected bool colorrectStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            ColorRectangle colrectFrame = new ColorRectangle(this.m_coreContext, _xmlAttributes["id"].Value, this.m_currFrame);
            this.ReadFrameAttributes(colrectFrame, _xmlAttributes);
            this.PushCurrentFrame(colrectFrame);
            return true;
        }

        protected bool colorrectEndTagEventHandler(string _strName)
        {
            this.PopCurrentFrame();
            return true;
        }

        protected bool textStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            Text txtFrame = new Text(this.m_coreContext, _xmlAttributes["id"].Value, this.m_currFrame);
            this.ReadFrameAttributes(txtFrame, _xmlAttributes);
            txtFrame.StringID = _xmlAttributes["stringid"].Value;
            if (null != _xmlAttributes.GetNamedItem("hjustification"))
            {
                string strHJustification = _xmlAttributes["hjustification"].Value;
                if ("left" == strHJustification)
                {
                    txtFrame.HJustification = Text.EHorizJustification.Left;
                }
                else if ("center" == strHJustification)
                {
                    txtFrame.HJustification = Text.EHorizJustification.Center;
                }
                else if ("right" == strHJustification)
                {
                    txtFrame.HJustification = Text.EHorizJustification.Right;
                }
            }
            if (null != _xmlAttributes.GetNamedItem("vjustification"))
            {
                string strVJustification = _xmlAttributes["vjustification"].Value;
                if ("top" == strVJustification)
                {
                    txtFrame.VJustification = Text.EVertJustification.Top;
                }
                else if ("center" == strVJustification)
                {
                    txtFrame.VJustification = Text.EVertJustification.Center;
                }
                else if ("bottom" == strVJustification)
                {
                    txtFrame.VJustification = Text.EVertJustification.Bottom;
                }
            }
            if (null != _xmlAttributes.GetNamedItem("wrap"))
            {
                if ("char" == _xmlAttributes["wrap"].Value)
                {
                    txtFrame.WordWrap = Text.EWrap.Char;
                }
                else if ("word" == _xmlAttributes["wrap"].Value)
                {
                    txtFrame.WordWrap = Text.EWrap.Word;
                }
                else if ("none" == _xmlAttributes["wrap"].Value)
                {
                    txtFrame.WordWrap = Text.EWrap.None;
                }
            }
            this.PushCurrentFrame(txtFrame);
            return true;
        }

        protected bool textEndTagEventHandler(string _strName)
        {
            this.PopCurrentFrame();
            return true;
        }

        protected bool texcolrectStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            TextureColorRectangle texcolrectFrame = new TextureColorRectangle(this.m_coreContext, _xmlAttributes["id"].Value, this.m_currFrame);
            this.ReadFrameAttributes(texcolrectFrame, _xmlAttributes);
            texcolrectFrame.Albedo = this.m_coreContext.GetData<TextureManager>("TextureManager").GetTexture(_xmlAttributes["textureid"].Value);
            this.PushCurrentFrame(texcolrectFrame);
            return true;
        }

        protected bool texcolrectEndTagEventHandler(string _strName)
        {
            this.PopCurrentFrame();
            return true;
        }

        protected bool childrenStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            return true;
        }

        protected bool childrenEndTagEventHandler(string _strName)
        {
            return true;
        }

        protected bool scaleStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            this.m_currFrame.Scale = new Vector2(float.Parse(_xmlAttributes["x"].Value), float.Parse(_xmlAttributes["y"].Value));
            return true;
        }

        protected bool scaleEndTagEventHandler(string _strName)
        {
            return true;
        }

        protected bool templateStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            string strTemplate = _xmlAttributes["id"].Value;
            if (null == this.m_uiManager.GetTemplate(strTemplate))
            {
                Template templateFrame = new Template(this.m_coreContext, strTemplate, this.m_currFrame);
                this.PushCurrentScene(templateFrame);
                this.ReadFrameAttributes(templateFrame, _xmlAttributes);
                this.PushCurrentFrame(templateFrame);
                return true;
            }
            throw new Exception(string.Format("template {0} has already been declared", strTemplate));
        }

        protected bool templateEndTagEventHandler(string _strName)
        {
            Template templateFrame = this.m_currFrame as Template;
            this.m_uiManager.AddTemplate(templateFrame);
            this.PopCurrentFrame();
            this.PopCurrentScene();
            return true;
        }

        protected bool templatelistStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            TemplateList templateListFrame = new TemplateList(this.m_coreContext, _xmlAttributes["id"].Value, this.m_currFrame);
            this.ReadFrameAttributes(templateListFrame, _xmlAttributes);
            this.PushCurrentFrame(templateListFrame);
            string strTemplate = _xmlAttributes["templateid"].Value;
            Template template = this.m_uiManager.GetTemplate(strTemplate);
            if (null == template)
            {
                this.m_uiManager.LoadScene(strTemplate + ".xml");
                template = this.m_uiManager.GetTemplate(strTemplate);
            }
            templateListFrame.Template = template;
            return true;
        }

        protected bool templatelistEndTagEventHandler(string _strName)
        {
            this.PopCurrentFrame();
            return true;
        }

        protected bool parametersStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            IParameterizable parameterizable = this.m_currFrame as IParameterizable;
            if (null != parameterizable)
            {
                return true;
            }
            throw new Exception(string.Format("{0} type has no IParameterizable interface", this.m_currFrame.GetType().ToString()));
        }

        protected bool parametersEndTagEventHandler(string _strName)
        {
            return true;
        }

        protected bool textparameterStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            IParameterizable parameterizable = this.m_currFrame as IParameterizable;
            return parameterizable.AddParameter(_xmlAttributes["source"].Value, _xmlAttributes["destination"].Value);
        }

        protected bool textparameterEndTagEventHandler(string _strName)
        {
            return true;
        }

        protected bool layoutStartTagEventHandler(string _strName, XmlAttributeCollection _xmlAttributes)
        {
            ILayout layout = this.m_currFrame as ILayout;
            string strValue = this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "rows", "1");
            int rows = ("children" == strValue) ? LayoutProcessor.ChildrenCount : int.Parse(strValue);
            strValue = this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "columns", "1");
            int columns = ("children" == strValue) ? LayoutProcessor.ChildrenCount : int.Parse(strValue);
            strValue = this.m_coreContext.CoreManager.GetXmlAttributeValue(_xmlAttributes, "feedrowfirst", "false");
            bool feedrowfirst = bool.Parse(strValue);
            layout.SetLayout(rows, columns, feedrowfirst);
            return true;
        }

        protected bool layoutEndTagEventHandler(string _strName)
        {
            return true;
        }
    }
}
